package EventSourcing;

import java.util.Vector;

import android.util.Log;

public class EventQueue {

	 // the stored event
	Vector<TrackableEvent> v;
	
	// the pointer indicates the position where the last element can be found
	private int pointer; 										
	
	// the list of Listeners that should be informed when the higher Bound is reached
	private Vector<BoundListener> higherBoundListeners; 
	
	
	//the list of Listeners that should be informed when the lower Bound is reached
	private Vector<BoundListener> lowerBoundListeners;

	/**
	 * constructor of the event sourcing class
	 */
	public EventQueue() {
		v = new Vector<TrackableEvent>();
		higherBoundListeners = new Vector<BoundListener>();
		lowerBoundListeners = new Vector<BoundListener>();
		setPointer(0);
	}

	/**
	 * decreases the pointer and informs the bound listeners
	 */
	private void decreasePointer() {
		setPointer(getPointer() - 1);
		if (pointerIsAtStart()){
			for (int i = 0; i<lowerBoundListeners.size();i++){
				lowerBoundListeners.get(i).boundReached();
			}
		}
		
		// the pointer was just at the end point and now not anymore so inform the higherBoundListeners
		if (getPointer()+1>= v.size()){
			for (int i = 0; i<higherBoundListeners.size();i++){
				higherBoundListeners.get(i).boundLeft();
			}
		}
	}

	/**
	 * increases the pointer and informs the bound listeners
	 */
	private void increasePointer() {
		setPointer(getPointer() + 1);
		
		if (pointerIsAtEnd()){
			for (int i = 0; i<higherBoundListeners.size();i++){
				higherBoundListeners.get(i).boundReached();
			}
		}
		
		// the pointer was just at the starting point and now not anymore so inform the lowerBoundListeners
		if (getPointer()-1<= 0){
			for (int i = 0; i<lowerBoundListeners.size();i++){
				lowerBoundListeners.get(i).boundLeft();
			}
		}
	}

	/**
	 * adds at the last position, the pointer position and increases the pointer
	 * @param pde
	 */
	public void add(TrackableEvent pde) {
		// remove elements greater then pointer
		if (getPointer() < v.size()) {
			for (int i = v.size() - 1; i >= getPointer(); i--) {
				v.remove(i);
			}
		}

		v.add(getPointer(), pde);
		increasePointer();
		Log.d("PIPEGAME", "add " + getPointer() + "size " + v.size());
	}

	/**
	 *  makes a step forwards, increases the pointer
	 * @return the element at the pointer position
	 */
	public TrackableEvent next() {
		Log.d("PIPEGAME", "next " + getPointer() + "size " + v.size());
		increasePointer();
		return v.get(getPointer() - 1);
	}

	/**
	 * makes a step backwards and decreases the pointer
	 * @return the element at the pointer position 
	 */
	public TrackableEvent last() {
		Log.d("PIPEGAME", "last " + getPointer() + "size " + v.size());
		decreasePointer();
		return v.get(getPointer());
	}

	/**
	 * 
	 * @return if the pointer is at the starting point
	 */
	public boolean pointerIsAtStart() {
		return (getPointer() <= 0);
	}
	
	/**
	 * 
	 * @return if the pointer is at the end
	 */
	public boolean pointerIsAtEnd() {
		return (getPointer() >= v.size());
	}

	/**
	 * adds a bound listener, that will be informed when the bound is reached and left
	 * @param lowerBoundListener the BoundListener
	 * @param bound the type of the Bound - can be found in the BoundListener class
	 */
	public void addBoundListener(BoundListener lowerBoundListener, int bound) {
		if (bound == BoundListener.LOWERBOUND) {
			this.lowerBoundListeners.add(lowerBoundListener);
			
			if (pointerIsAtStart()){
				lowerBoundListener.boundReached();
			}
		} else if (bound == BoundListener.HIGHERBOUND) {
			this.higherBoundListeners.add(lowerBoundListener);
			
			if (pointerIsAtEnd()){
				lowerBoundListener.boundReached();
			}
		}
	}

	public int size() {
		return v.size();
	}

	public int getPointer() {
		return pointer;
	}

	private void setPointer(int pointer) {
		this.pointer = pointer;
	}
}
